/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package queenb.net.datacontrol;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import queenb.net.annotation.FunctionName;
import queenb.net.annotation.Mapping;

/**
 *
 * @author thanhct
 */
public class DataControl<T> {

    private static final int MAPPING_OK = 1;
    private static final int MAPPING_NULL = -1;
    private static final int MAPPING_FAILT = 0;
    private static final String NULL = "NULL";

    public List<T> mappingIndex(List listData, Class clazzEntity, FunctionName functionName) throws InstantiationException, IllegalAccessException, Exception {
        List<T> lstEntity = new ArrayList<T>();
        for (int i = 0; i < listData.size(); i++) {
            Object[] object = (Object[]) listData.get(i);
            Object objClazz = clazzEntity.newInstance();
            Field[] fields = clazzEntity.getDeclaredFields();
            for (int j = 0; j < fields.length; j++) {
                Field field = fields[j];
                Mapping mapping = field.getAnnotation(Mapping.class);
                if (validateMapping(mapping) == MAPPING_OK) {
                    FunctionName[] currentFunctions = mapping.procedureNames();
                    int functionIndex = validateFunction(currentFunctions, functionName);
                    if (functionIndex < 0) {
                        continue;
                    }
                    if (functionIndex != -1) {
                        int index = mapping.index()[functionIndex];
                        if (!validateType(object[index], objClazz, field)) {
                            throw new Exception("type of \"" + getExplicitField(field) + "\" not match with type of object[" + index + "] in function name: " + functionName + ":" + object[index].getClass());
                        }
                    }
                } else if (validateMapping(mapping) == MAPPING_FAILT) {
                    throw new Exception("mapping fail:array of index and function name not the same length");
                }
            }
            lstEntity.add((T) objClazz);
        }
        return lstEntity;
    }

    /**
     * this one to validate functionName when register a mapping annotation for field
     * function in a field have to map with function in parameter
     * @param functionNames
     * @param functionName
     * @return
     */
    private int validateFunction(FunctionName[] functionNames, FunctionName functionName) {
        int functionIndex = -1;
        for (int k = 0; k < functionNames.length; k++) {
            FunctionName functionName1 = functionNames[k];
            if (functionName1.equals(functionName)) {
                functionIndex = k;
                break;
            }
        }
        return functionIndex;
    }

    /**
     * this function to validate Mapping annotation length of index hava to equal with procedureName length
     * @param mapping
     * @return -1 mapping is null, 0 mapping not match,1 mapping ok
     */
    private int validateMapping(Mapping mapping) {
        if (mapping != null) {
            if (mapping.index().length == mapping.procedureNames().length) {
                return MAPPING_OK;
            } else {
                return MAPPING_FAILT;
            }
        }
        return MAPPING_NULL;
    }

    private boolean validateType(Object object, Object objClazz, Field field) throws IllegalArgumentException, IllegalAccessException {
        if (object.getClass().equals(field.getType())) {
            field.set(objClazz, object);
            return true;
        }
        return false;
    }

    private String getExplicitField(Field field) {
        if (field != null) {
            return Modifier.toString(field.getModifiers()) + " " + field.getType() + " " + field.getName();
        }
        return NULL;
    }
    protected List<T> find(DataStatement paraData, Class<T> tClazz) throws SQLException, InstantiationException, IllegalAccessException {
        return paraData.executeQuery(tClazz);
    }

    protected int update(DataStatement dataStatement, Class<T> tClass) throws SQLException {
        int reVal = dataStatement.executeUpdate(tClass);
        return reVal;
    }
     protected int updateNoOutParam(DataStatement dataStatement, Class<T> tClass) throws SQLException {
        int reVal = dataStatement.executeUpdateNoOutParam(tClass);
        return reVal;
    }
     

    protected Object updateReturnObject(DataStatement dataStatement, Class<T> tClass) throws SQLException {
        Object reVal = dataStatement.executeUpdateReturnObject(tClass);
        return reVal;
    }
    protected List updateMultiReturn(DataStatement dataStatement, Class<T> tClass) throws SQLException {
        List reVal = dataStatement.executeUpdateMultiReturn(tClass);
        return reVal;
    }
    protected List updateMultiReturnNew(DataStatement dataStatement, Class<T> tClass) throws SQLException {
        List reVal = dataStatement.executeUpdateMultiReturnNew(tClass);
        return reVal;
    }
   

}
